﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Tomahawk.Runtime.Serialization;

namespace Tomahawk.Runtime.Logic.UI
{
    #region "Common Delegates"

    /// <summary>
    /// Delegate for user activation on control events
    /// </summary>
    public delegate void ControlUserActivation(XUIControl sourceControl);

    /// <summary>
    /// Delegate for communication between scenes, controls and client code
    /// </summary>
    public delegate void ControlNotification(string message);

    #endregion

    /// <summary>
    /// An XUIControl is each one of the widgets that compose an XUIScene
    /// </summary>
    public class XUIControl : XUIObject
    {

        /// <summary>
        /// Make this object pseudo-abstract by protecting the constructor
        /// </summary>
        protected XUIControl()
        {
            this.childControls = new SerializableList<XUIControl>();
        }

        #region "Parentship"

        /// <summary>
        /// XUIScene object this controls ultimatelly belongs to
        /// </summary>
        private XUIScene parentUIScene;

        /// <summary>
        /// XUIScene object this controls ultimatelly belongs to
        /// </summary>
        public XUIScene ParentUIScene
        {
            get { return this.parentUIScene; }
        }

        /// <summary>
        /// Traverse up the object hierarchy until it founds the parent UIScene and stores it
        /// for future use
        /// </summary>
        private void findParentUIScene()
        {
            XUIObject xuioParent = this;
            parentUIScene = xuioParent as XUIScene;
            while (parentUIScene == null)
            {
                xuioParent = xuioParent.Parent as XUIObject;
                parentUIScene = xuioParent as XUIScene;
            }
        }

        #endregion

        #region "Child Controls"

        /// <summary>
        /// List of child controls
        /// </summary>
        private SerializableList<XUIControl> childControls;

        /// <summary>
        /// List of child controls
        /// </summary>
        [XmlElement("ChildControls")]
        public SerializableList<XUIControl> ChildControls
        {
            get { return childControls; }
            set { childControls = value; }
        }

        /// <summary>
        /// Add a new child control to this control
        /// </summary>
        public void AddChildControl(XUIControl control)
        {
            //the child control cannot be of type XUIScene
            XUIScene scene = control as XUIScene;
            if (scene != null) throw new UISceneCannotBeChildException();

            //make it a child of this control
            if (control.Parent != this)
                control.SetParent(this);

            //add to components array
            childControls.Add(control);

            //notify derived code
            this.OnControlAddded(control);
        }

        /// <summary>
        /// Override this to provide custom indexing of controls
        /// </summary>
        protected virtual void OnControlAddded(XUIControl control)
        {
        }

        /// <summary>
        /// Remove a child control to this control
        /// </summary>
        public void RemoveChildControl(XUIControl control)
        {
            //remove from array
            if (control.Parent == this) control.SetParent(null);
            childControls.Remove(control);

            //notify derived code
            this.OnControlRemoved(control);
        }

        /// <summary>
        /// Override this to provide custom control removing logic
        /// </summary>
        protected virtual void OnControlRemoved(XUIControl control)
        {
        }

        #endregion

        /// <summary>
        /// Initialization
        /// </summary>
        protected override void OnInitialize()
        {
            base.OnInitialize();

            //find the parent ui scene object
            this.findParentUIScene();

            //All the controls added at this point (added via Xml Archetype)
            //must be registered in the world, as a child of this one
            foreach (XUIControl control in this.childControls)
            {
                //register the control in the world
                XWorld.Instance.registerObject(this, "", control);
            }
        }

        #region "Visibility"

        protected bool visible = true;

        /// <summary>
        /// Indicates wheter the control is visible or not
        /// </summary>
        [XmlIgnore()]
        public bool Visible
        {
            get { return this.Visible; }
            set
            {
                this.OnChangeVisibility(value);
                this.visible = value;
            }
        }

        /// <summary>
        /// Override this to provide logic for visibility change
        /// </summary>
        protected virtual void OnChangeVisibility(bool newValue)
        {
            foreach (XUIControl control in this.childControls)
            {
                control.Visible = newValue;
            }
        }

        #endregion

        #region "Exceptions"

        public class UISceneCannotBeChildException : UIBaseException
        {
            public UISceneCannotBeChildException()
                : base(Debug.Exceptions.ExceptionSeverity.Error,
                    "And XUIScene object cannot be used as a child of another controls", null) { }
        }

        #endregion

        #region "Readyness"

        /// <summary>
        /// A control is ready by default when all of its child control are
        /// </summary>
        protected override bool checkResourcesReady()
        {
            bool retVal = true;
            foreach (XUIControl control in this.childControls)
            {
                retVal = retVal && control.IsReady;
            }
            return base.checkResourcesReady() && retVal;
        }

        #endregion

    }
}
